package org.jsoup.parser;

import org.jsoup.helper.DescendableLinkedList;
import org.jsoup.helper.Validate;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;

/**
 * @author Jonathan Hedley
 */
abstract class TreeBuilder {
    CharacterReader reader;
    Tokeniser tokeniser;
    protected Document doc; // current doc we are building into
    protected DescendableLinkedList<Element> stack; // the stack of open elements
    protected String baseUri; // current base uri, for creating new elements
    protected Token currentToken; // currentToken is used only for error tracking.
    protected ParseErrorList errors; // null when not tracking errors

    protected void initialiseParse(String input, String baseUri, ParseErrorList errors) {
        Validate.notNull(input, "String input must not be null");
        Validate.notNull(baseUri, "BaseURI must not be null");

        doc = new Document(baseUri);
        if (baseUri.startsWith("http://tvlistings.zap2it.com/tvlistings/ZCGrid.do")) {
        	//strip all html from before and after the grid
        	int start = input.indexOf("<div id=\"zc-shell\" class=\"zc-grid\">");
        	int end = input.indexOf("<div id=\"zc-tooltip\">");
        	input = input.substring(start, end) + "</div>";
        	
        	//remove all carriage returns
        	input = input.replace("\n", "");
        	//remove all the station attribute classes and links
        	input = input.replaceAll("class=\"zc-st-a\" href=\"http://tvlistings.zap2it.com/tvlistings/ZCSGrid.do?stnNum=[0-9]+&channel=[0-9]+\"", "");
        	//remove all CC (closed caption) tags
        	input = input.replaceAll("<span class=\"zc-ic-s zc-ic-cc\">CC</span>", "");
        	//remove all LOOR channels
        	input = input.replaceAll("<table cellspacing=\"0\" class=\"zc-row\" id=\"zc-st-14786\".+</table>", "");
        	//remove all PPV channels
        	//input = input.replaceAll("^.+\">.+PPV.+</a>.+$", "");
        }
        
        reader = new CharacterReader(input);
        this.errors = errors;
        tokeniser = new Tokeniser(reader, errors);
        stack = new DescendableLinkedList<Element>();
        this.baseUri = baseUri;
    }

    Document parse(String input, String baseUri) {
        return parse(input, baseUri, ParseErrorList.noTracking());
    }

    Document parse(String input, String baseUri, ParseErrorList errors) {
        initialiseParse(input, baseUri, errors);
        runParser();
        return doc;
    }

    protected void runParser() {
        while (true) {
            Token token = tokeniser.read();
            
            process(token);

            if (token.type == Token.TokenType.EOF)
                break;
        }
    }

    protected abstract boolean process(Token token);

    protected Element currentElement() {
        return stack.getLast();
    }
}
